package gambit.jogador;

import gambit.core.Tabuleiro;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.StringTokenizer;

public class Aprendizado {

	private float[] alpha = {0.9f,-0.2f,0.5f,-0.8f,-0.4f,0.2f,0.9f,-0.2f,0.1f,-0.5f,-0.3f,-0.4f,-0.7f};
	private int[] heuristicasAntigas = new int[Utilidade.NUMERO_HEURISTICAS];
	private int[] heuristicasNovas = new int[Utilidade.NUMERO_HEURISTICAS];
	private int[] pesosAntigos = new int[Utilidade.NUMERO_HEURISTICAS];
	private int[] pesosNovos = new int[Utilidade.NUMERO_HEURISTICAS];

	private FileOutputStream fOut;
	private FileInputStream fIn;
	private PrintStream ps;
	private String nomeJogador;

	public Aprendizado(String nomeJogador) {

		this.nomeJogador = nomeJogador;
		Tabuleiro tabuleiro = new Tabuleiro();
		int[] valorCasa = tabuleiro.getCasas();

		setHeuristicasNovas(Utilidade.getValorHeuristicas(valorCasa));
		setPesosAntigos(Utilidade.getPesos());

		try {
			fIn = new FileInputStream("/home/guilherme/" + nomeJogador + ".dam");
			BufferedReader br = new BufferedReader(new InputStreamReader(fIn));
			String strLine = null, tmp;
			
			while ((tmp = br.readLine()) != null) {
				strLine = tmp;
			}
				
			String lastLine = strLine;
			System.out.println("[entrada]\n" + lastLine);
	
			fIn.close();

			String[] pesos = new String[Utilidade.NUMERO_HEURISTICAS];
			StringTokenizer st = new StringTokenizer(lastLine);
			
			for (int i = 0; i < Utilidade.NUMERO_HEURISTICAS; i++) {
				pesos[i] = st.nextToken();
				pesosNovos[i] = Integer.parseInt(pesos[i]);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

//		System.out.println("[saida]\n" + getPesosNovos()[0] + "\t" + getPesosNovos()[1]
//				+ "\t" + getPesosNovos()[2] + "\t" + getPesosNovos()[3] + "\t"
//				+ getPesosNovos()[4] + "\t" + getPesosNovos()[5] + "\t"
//				+ getPesosNovos()[6] + "\t" + getPesosNovos()[7] + "\t"
//				+ getPesosNovos()[8] + "\t" + getPesosNovos()[9] + "\t"
//				+ getPesosNovos()[10] + "\n");

	}

	public void atualizar(Tabuleiro tabuleiro) {

		setHeuristicasAntigas(getHeuristicasNovas());
		setPesosAntigos(getPesosNovos());
		setHeuristicasNovas(Utilidade.getValorHeuristicas(tabuleiro.getCasas()));

		int[] sub = new int[Utilidade.NUMERO_HEURISTICAS];

		for (int i = 0; i < Utilidade.NUMERO_HEURISTICAS; i++) {
			
			//adicionar valor de threshold
			sub[i] = (int) (getPesosAntigos()[i] + (10*calcularAlpha(i) * (getHeuristicasNovas()[i] - getHeuristicasAntigas()[i])));

		}

		setPesosNovos(sub);
		Utilidade.setPesos(getPesosNovos());

//		ps.println(getPesosNovos()[0] + "\t" + getPesosNovos()[1] + "\t"
//				+ getPesosNovos()[2] + "\t" + getPesosNovos()[3] + "\t"
//				+ getPesosNovos()[4] + "\t" + getPesosNovos()[5] + "\t"
//				+ getPesosNovos()[6] + "\t" + getPesosNovos()[7] + "\t"
//				+ getPesosNovos()[8] + "\t" + getPesosNovos()[9] + "\t"
//				+ getPesosNovos()[10] + "\t" + getPesosNovos()[11] + "\t"
//				+ getPesosNovos()[12]);

		System.out.println("[pesos]\n" + getPesosNovos()[0] + "\t" + getPesosNovos()[1]
				+ "\t" + getPesosNovos()[2] + "\t" + getPesosNovos()[3] + "\t"
				+ getPesosNovos()[4] + "\t" + getPesosNovos()[5] + "\t"
				+ getPesosNovos()[6] + "\t" + getPesosNovos()[7] + "\t"
				+ getPesosNovos()[8] + "\t" + getPesosNovos()[9] + "\t"
				+ getPesosNovos()[10] + "\t" + getPesosNovos()[11] + "\t"
				+ getPesosNovos()[12]);
		
		System.out.println("[heuristicas]\n" + getHeuristicasNovas()[0] + "\t"
				+ getHeuristicasNovas()[1] + "\t" + getHeuristicasNovas()[2]
				+ "\t" + getHeuristicasNovas()[3] + "\t"
				+ getHeuristicasNovas()[4] + "\t" + getHeuristicasNovas()[5]
				+ "\t" + getHeuristicasNovas()[6] + "\t"
				+ getHeuristicasNovas()[7] + "\t" + getHeuristicasNovas()[8]
				+ "\t" + getHeuristicasNovas()[9] + "\t"
				+ getHeuristicasNovas()[10] + "\t" + getHeuristicasNovas()[11]
				+ "\t" + getHeuristicasNovas()[12] + "\n");
	}
	
	private float calcularAlpha(int heuristica){
		switch(heuristica){
		//hpos
		case(0):
			
			alpha[0]=(alpha[0]>0.07)?(alpha[0]-0.07f):alpha[0];
			return alpha[0];
		//havançoAliado
		case 1:
			return alpha[1];
		//hAvançoInimigo
		case 2:
			alpha[2]=(alpha[2]>0.07)?(alpha[2]-0.07f):alpha[2];
			return alpha[2];
		//hMobilidade
		case 3:
			alpha[3]=(alpha[3]<-0.08)?(alpha[3]+0.08f):0;
			return alpha[3];
		//hDamas
		case 4:
			return alpha[4];
		//hVala
		case 5:
			return alpha[5];
		//Retaguarda
		case 6:
			return alpha[6];
		//dyke
		case 7:
			return alpha[7];
		//thret
		case 8:
			return alpha[8]; //
		//anticadeia
		case 9:
			return alpha[9];
		//damaKiller
		case 10:
			return alpha[10];
		//numero de peças
		case 11:
			return alpha[11];
		case 12:
			return alpha[12];
			default: return 0;
		}
	}
	
	public void persistir(boolean backup){
		
		String ext = backup ? ".bak" : ".dam";

		try {
			fOut = new FileOutputStream("/home/guilherme/" + this.nomeJogador + ext);
			ps = new PrintStream(fOut);
			ps.println(getPesosNovos()[0] + "\t" + getPesosNovos()[1] + "\t"
					+ getPesosNovos()[2] + "\t" + getPesosNovos()[3] + "\t"
					+ getPesosNovos()[4] + "\t" + getPesosNovos()[5] + "\t"
					+ getPesosNovos()[6] + "\t" + getPesosNovos()[7] + "\t"
					+ getPesosNovos()[8] + "\t" + getPesosNovos()[9] + "\t"
					+ getPesosNovos()[10] + "\t" + getPesosNovos()[11] + "\t"
					+ getPesosNovos()[12]);
			
			ps.close();
			fOut.close();

		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

	public float[] getAlpha() {
		return alpha;
	}

	public void setAlpha(float[] alpha) {
		this.alpha = alpha;
	}

	public int[] getHeuristicasAntigas() {
		return heuristicasAntigas;
	}

	public void setHeuristicasAntigas(int[] heuristicasAntigas) {
		this.heuristicasAntigas = heuristicasAntigas;
	}

	public int[] getHeuristicasNovas() {
		return heuristicasNovas;
	}

	public void setHeuristicasNovas(int[] heuristicasNovas) {
		this.heuristicasNovas = heuristicasNovas;
	}

	public int[] getPesosAntigos() {
		return pesosAntigos;
	}

	public void setPesosAntigos(int[] pesosAntigos) {
		this.pesosAntigos = pesosAntigos;
	}

	public int[] getPesosNovos() {
		return pesosNovos;
	}

	public void setPesosNovos(int[] pesosNovos) {
		this.pesosNovos = pesosNovos;
	}

}
